#include <pthread.h>
#include "mypipe.h"

/**
 * 定义一个队列结构体
 */
struct mypipe_st
{
    int head;
    int tail;
    char data[PIPESIZE];
    int datasize;
	int count_rd;
	int count_wr;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
};

int mypipe_register(mypipe_t *ptr, int opmap)
{
	
	struct mypipe_st *me = ptr;

	pthread_mutex_lock(&me->mutex);
	if(opmap & MYPIPE_READ)
		me->count_rd++;
	if(opmap & MYPIPE_WRITE)
		me->count_wr++;

	/*
	 * 管道中只有满足，读者和写者同事存在，才会进行通信，否则关闭
	 * */
	pthread_cond_broadcast(&me->cond);	// 通知其他读者是否满足，读者和写者同事存在

	while (me->count_rd < 0 || me->count_wr < 0) {
		pthread_cond_wait(&me->cond, &me->mutex);
	}
	pthread_mutex_unlock(&me->mutex);
	
	return 0;
}

int mypipe_unregister(mypipe_t *ptr, int opmap)
{
	
	return 0;
}

mypipe_t *mypipe_init(void)
{
    struct mypipe_st *me;

    me = malloc(sizeof(*me));
    if(me == NULL)
        return NULL;
    me->head = 0;
    me->tail = 0;
    me->datasize = 0;

    pthread_mutex_init(&me->mutex, NULL);
    pthread_cond_init(&me->cond, NULL);

    return me;
}

static int next(int n)
{
	if(n >= PIPESIZE)
		return 0;
	else
		return n++;
}

/*
 * 单字节读取数据
 * */
static int mypipe_readbyte_unlocked(struct mypipe_st *ptr, char *datap)
{
	if(ptr->datasize <= 0)
		return -1;

	*datap = ptr->data[ptr->head]; 	// 管道头部读取数据
	ptr->head = next(ptr->head);	// 管道中的内容标记位不断向前移动
	ptr->datasize--;				// 数据被取走，数量减少
	return 0;
}

int mypipe_read(mypipe_t *ptr, void *buf, size_t size)
{
    struct mypipe_st *me = ptr;
	int i;
	pthread_mutex_lock(&me->mutex);
	while(me->datasize <= 0 && me->count_wr > 0)
		pthread_cond_wait(&me->cond, &me->mutex);		// 管道中没有数据的时候，进行等待
	
	if(me->datasize <= 0 && me->count_wr <= 0)
	{
		pthread_mutex_unlock(&me->mutex);
		return 0;
	}
	for (i = 0; i < size; i++) {
		if(mypipe_readbyte_unlocked(me, (buf+1)) < 0)	// 开始有数据的时候读取数据
			break;
	}
	pthread_cond_broadcast(&me->cond);					// 通知写者，已经有空闲的位置可以写
	pthread_mutex_unlock(&me->mutex);
	// 将读取到个数进行返回	
	return i;
}

int mypipe_write(mypipe_t *ptr, void *buf, size_t size)
{
    struct mypipe_st *me = ptr;

}

int mypipe_destory(mypipe_t *ptr)
{
    
    struct mypipe_st *me = ptr;

    pthread_mutex_destroy(&me->mutex);
    pthread_cond_destroy(&me->cond);

    free(me);

	return 0;
}

